﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DbDoc;
using DbDoc.BusinessObjects;
using DbDoc.Provider.Persistence;
using DbDoc.Provider.Source;

namespace DbDoc.BusinessManager
{
    public static class DatabaseManager
    {
        private static List<string> includeDatabases = new List<string>();
        private static List<string> excludeDatabases = new List<string>();

        #region Properties
        public static string SourceConnectionInfo
        {
            get { return SourceProviderManager.Provider.ConnectionInfo; }
        }

        public static string PersistenceConnectionInfo
        {
            get { return PersistenceProviderManager.Provider.ConnectionInfo; }
        }

        public static string SourceStorageName
        {
            get { return SourceProviderManager.Provider.StorageName; }
        }

        public static string PersistenceStorageName
        {
            get { return PersistenceProviderManager.Provider.StorageName; }
        }

        public static string SourceExcludedDatabases
        {
            get { return string.Join(",",SourceProviderManager.Provider.ExcludedDatabasesList); }
        }
        #endregion

        public static IList<Database> GetDatabases(bool includeChildren)
        {
            IList<Database> databases = PersistenceProviderManager.Provider.GetDatabases();
            if (includeChildren)
            {
                foreach (Database db in databases)
                {
                    db.Tables = GetTables(db);
                    foreach (Table tbl in db.Tables)
                        tbl.Columns = GetColumns(db, tbl);
                    db.Procs = GetStoredProcs(db);                    
                }
            }
            return databases;
        }

        public static IList<Database> GetDatabases()
        {
            return GetDatabases(false);
        }

        public static IList<Table> GetTables(DbDoc.BusinessObjects.Database db)
        {
            return PersistenceProviderManager.Provider.GetTables(db);
        }

        public static IList<StoredProc > GetStoredProcs(DbDoc.BusinessObjects.Database db)
        {
            return PersistenceProviderManager.Provider.GetStoredProcs(db);
        }

        public static IList<Column > GetColumns(DbDoc.BusinessObjects.Database db, Table tbl)
        {
            return PersistenceProviderManager.Provider.GetColumns(db, tbl);
        }    

        public static void SaveDbObject(DbObject dbobj)
        {
            PersistenceProviderManager.Provider.SaveDbObject(dbobj);
        }

        public static void UpdateDbObject(DbObject dbobj)
        {
            PersistenceProviderManager.Provider.UpdateDbObject(dbobj);
        }

        public static IEnumerable<Comment> GetCommentsHistory(DbObject obj)
        {
            return PersistenceProviderManager.Provider.GetCommentsHistory(obj);
        }

        #region Synchronization
        public static void Synchronize()
        {
            SynchronizeDatabases();
        }

        private static  void SynchronizeDatabases()
        {
            bool includeSystemObjects = Boolean.Parse(PersistenceProviderManager.Provider.GetByKey(Constants.Settings.INCLUDE_SYSTEM_OBJECTS).Value.ToString());

            IList<string> serverDatabases = SourceProviderManager.Provider.GetServerDatabases();
            IList<Database> databases = PersistenceProviderManager.Provider.GetDatabases();
            IList<Database> deletedDatabases = new List<Database>();
            foreach (string sDb in serverDatabases)
            {
                bool found = false;
                foreach (Database db in databases)
                {
                    if (string.Compare(db.Name, sDb) == 0)
                    {
                        found = true;
                        break;
                    }
                    if (!serverDatabases.Contains(db.Name) && !deletedDatabases.Contains(db))
                        deletedDatabases.Add(db);

                }
                if (!found && !excludeDatabases.Contains(sDb.Trim()))
                {
                    Database newDb = new Database();
                    newDb.Name = sDb;
                    SaveDbObject(newDb);
                    databases.Add(newDb);
                }
            }

            foreach (Database db in deletedDatabases)
            {
                db.Deleted = true;
                UpdateDbObject(db);
            }

            databases = PersistenceProviderManager.Provider.GetDatabases();
            foreach (Database db in databases)
            {
                SynchronizeTables(db);
                SynchronizeStoredProcs(db, includeSystemObjects);
            }
        }

        public static void SynchronizeTables(Database database)
        {
            IList<string> serverTables = SourceProviderManager.Provider.GetServerTables(database.Name);
            IList<Table> tables = GetTables(database);
            foreach (string stbl in serverTables)
            {
                bool found = false;
                foreach (Table tbl in tables)
                {
                    if (string.Compare(tbl.Name, stbl) == 0)
                    {
                        found = true;
                        break;
                    }
                }
                if (!found)
                {
                    Database newDb = new DbDoc.BusinessObjects.Database();
                    Table newTable = new DbDoc.BusinessObjects.Table();
                    newTable.Name = stbl;
                    newTable.Parent = database;
                    SaveDbObject(newTable);
                }

            }
            tables = GetTables(database);
            foreach (Table tbl in tables)
                SynchronizeColumns(database, tbl);
        }

        public static void SynchronizeColumns(Database database, Table tbl)
        {
            IList<string> serverColumns = SourceProviderManager.Provider.GetServerColumns(database.Name, tbl.Name);
            IList<Column> columns = GetColumns(database, tbl);
            foreach (string scol in serverColumns)
            {
                bool found = false;
                foreach (Column col in columns)
                {
                    if (string.Compare(col.Name, scol) == 0)
                    {
                        found = true;
                        break;
                    }
                }
                if (!found)
                {
                    Column newColumn = new DbDoc.BusinessObjects.Column();
                    newColumn.Name = scol;
                    newColumn.Parent = tbl;
                    SaveDbObject(newColumn);
                }

            }
        }

        public static void SynchronizeViews(Database database) { }

        public static void SynchronizeStoredProcs(Database database, bool includeSystemObjects) 
        {
            IList<string> serverProcs = SourceProviderManager.Provider.GetServerStoredProcs (database.Name, includeSystemObjects);
            IList<StoredProc> procs = GetStoredProcs (database);
            foreach (string sprocs in serverProcs)
            {
                bool found = false;
                foreach (StoredProc proc in procs)
                {
                    if (string.Compare(proc.Name, sprocs) == 0)
                    {
                        found = true;
                        break;
                    }
                }
                if (!found)
                {
                    Database newDb = new DbDoc.BusinessObjects.Database();
                    StoredProc newProc = new DbDoc.BusinessObjects.StoredProc();
                    newProc.Name = sprocs;
                    newProc.Parent = database;
                    SaveDbObject(newProc);
                }

            }
        }

        public static void SynchronizeFunctions(Database database) { }
        #endregion
    }
}
